﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using GameControls;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;

namespace XNAControlRenderer
{
    public sealed class XNAControlRenderer : IControlRenderer
    {
        #region Constants
        #endregion

        #region Properties
        private GraphicsDevice mGraphicsDevice;
        private SpriteBatch mSpriteBatch;

        private bool mIsBeginExecuted;
        #endregion

        #region Events
        #endregion

        #region Constructors
        public XNAControlRenderer(
            GraphicsDevice pGraphicsDevice,
            SpriteBatch pSpriteBatch)
        {
            mGraphicsDevice = pGraphicsDevice;
            mSpriteBatch = pSpriteBatch;

            mIsBeginExecuted = false;
        }
        #endregion

        #region Overriden Methods
        public void Begin()
        {
            if (!mIsBeginExecuted)
            {
                mIsBeginExecuted = true;
                mSpriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, mGraphicsDevice.RasterizerState);
            }
            else
            {
                string errorMessage = "There cannot be two Begin() calls without an End() call between.";
                throw new InvalidOperationException(errorMessage);
            }
        }

        public void End()
        {
            if (mIsBeginExecuted)
            {
                mIsBeginExecuted = false;
                mSpriteBatch.End();
            }
            else
            {
                string errorMessage = "End() cannot be called before Begin().";
                throw new InvalidOperationException(errorMessage);
            }
        }

        public void Render(ControlBase pControl)
        {
            if (!mIsBeginExecuted)
            {
                string errorMessage = "Begin() must be called before Render().";
                throw new InvalidOperationException(errorMessage);
            }

            mSpriteBatch.End();

            Rectangle? clippingRectangle = pControl.GetClippingRect();
            mGraphicsDevice.ScissorRectangle = clippingRectangle.HasValue ? clippingRectangle.Value : mGraphicsDevice.Viewport.Bounds;

            mSpriteBatch.Begin(SpriteSortMode.Deferred, null, null, null, mGraphicsDevice.RasterizerState);

            RenderImpl(pControl);
        }
        #endregion

        #region Methods
        private void RenderImpl(ControlBase pControl)
        {
            if (pControl is Label)
            {
                RenderLabel((Label)pControl);
            }
            else if (pControl is Button)
            {
                RenderButton((Button)pControl);
            }
            else if (pControl is Image)
            {
                RenderImage((Image)pControl);
            }
            else if (pControl is Slider)
            {
                RenderSlider((Slider)pControl);
            }
            else if (pControl is ScrollView)
            {
                RenderScrollView((ScrollView)pControl);
            }
            else
            {
                throw new NotImplementedException();
            }
        }

        private void RenderLabel(Label pLabel)
        {
            if (pLabel.IsTextValid())
            {
                mSpriteBatch.DrawString(pLabel.Font, pLabel.Text, pLabel.GetTextPosition(), pLabel.TextColor);
            }
        }

        private void RenderButton(Button pButton)
        {
            if (pButton.Texture != null)
            {
                mSpriteBatch.Draw(pButton.Texture, pButton.TransformedRect, pButton.GetColorForCurrentState());
            }
        }

        private void RenderImage(Image pImage)
        {
            if (pImage.Texture != null)
            {
                mSpriteBatch.Draw(pImage.Texture, pImage.TransformedRect, Color.White);
            }
        }

        private void RenderSlider(Slider pSlider)
        {
            mSpriteBatch.Draw(pSlider.Texture, pSlider.TransformedRect, Color.Black);
            mSpriteBatch.Draw(pSlider.Texture, pSlider.GetKnobRect(), Color.OrangeRed);
        }

        private void RenderScrollView(ScrollView pScrollView)
        {
        }
        #endregion

        #region Event Handlers
        #endregion

        #region Inner Classes
        #endregion
    }
}